package com.wyz.saas.common.utils;

import android.annotation.SuppressLint;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.geojson.GeoJsonReader;
import com.vividsolutions.jts.io.geojson.GeoJsonWriter;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public final class JacksonUtils {

    /**
     * 注意 序列和反序列 的 类需要有一个默认的无参数的构造器
     */
    static class JtsGeometryModule extends SimpleModule {
        private static final long serialVersionUID = 4188560927232308028L;

        public JtsGeometryModule() {
            this(new GeometryFactory());
        }

        public JtsGeometryModule(GeometryFactory geometryFactory) {
            super("JtsGeometryModule", Version.unknownVersion());
            GeoJsonWriter geoJsonWriter = new GeoJsonWriter(10);
            GeoJsonReader geoJsonReader = new GeoJsonReader(geometryFactory);
            addSerializer(Geometry.class, new JtsGeometrySerializer<>(geoJsonWriter));
            addDeserializer(Geometry.class, new JtsGeometryDeserializer<>(geoJsonReader));
            addDeserializer(Point.class, new JtsGeometryDeserializer<Point>(geoJsonReader));
            addDeserializer(MultiPoint.class, new JtsGeometryDeserializer<MultiPoint>(geoJsonReader));
            addDeserializer(LineString.class, new JtsGeometryDeserializer<LineString>(geoJsonReader));
            addDeserializer(MultiLineString.class, new JtsGeometryDeserializer<MultiLineString>(geoJsonReader));
            addDeserializer(Polygon.class, new JtsGeometryDeserializer<Polygon>(geoJsonReader));
            addDeserializer(MultiPolygon.class, new JtsGeometryDeserializer<MultiPolygon>(geoJsonReader));
            addDeserializer(GeometryCollection.class, new JtsGeometryDeserializer<GeometryCollection>(geoJsonReader));
        }

        @Override
        public void setupModule(SetupContext context) {
            super.setupModule(context);
        }
    }

    static class JtsGeometryDeserializer<T extends Geometry> extends JsonDeserializer<T> {

        private final GeoJsonReader geometryJSON;

        public JtsGeometryDeserializer() {
            this(new GeoJsonReader());
        }

        public JtsGeometryDeserializer(GeoJsonReader geometryJSON) {
            this.geometryJSON = geometryJSON;
        }

        @Override
        public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String text;
            if (p.getCurrentToken() == JsonToken.START_OBJECT) {
                ObjectMapper mapper = (ObjectMapper) p.getCodec();
                JsonNode jsonNode = mapper.readTree(p);
                text = jsonNode.toString();
            } else {
                text = p.getText();
            }
            if (text == null || text.length() <= 0)
                return null;
            Reader reader = new StringReader(text);
            Geometry geometry = null;
            try {
                geometry = geometryJSON.read(reader);
                T t = (T) geometry;
                return t;
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    static class JtsGeometrySerializer<T extends Geometry> extends JsonSerializer<T> {

        private final GeoJsonWriter geometryJSON;

        public JtsGeometrySerializer() {
            this(new GeoJsonWriter(10));
        }

        public JtsGeometrySerializer(GeoJsonWriter geometryJSON) {
            this.geometryJSON = geometryJSON;
        }

        @Override
        public void serialize(T geometry, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            StringWriter writer = new StringWriter();
            geometryJSON.write(geometry, writer);
            String jsonValue = writer.toString();
            gen.writeString(jsonValue);
        }
    }

    //时间序列化时变为时间戳
    static class LocalDateTimeToLongSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException, JsonProcessingException {
            jsonGenerator.writeNumber(value.getTime());
        }
    }

    //时间戳反序列化时间
    static class LongToLocalDateTimeDeserializer extends JsonDeserializer<Date> {

        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            return new Date(jsonParser.getLongValue());
        }
    }

    //时间序列化时变为字符串
    static class LocalDateTimeToStringSerializer extends JsonSerializer<Date> {

        @Override
        public void serialize(Date value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException, JsonProcessingException {
            jsonGenerator.writeNumber('\"'+format.format(value)+'\"');
        }
    }

    //时间戳反序列化时间
    static class StringToLocalDateTimeDeserializer extends JsonDeserializer<Date> {

        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            try {
                return format.parse(jsonParser.getValueAsString());
            } catch (java.text.ParseException e) {
                e.printStackTrace();
            }
            return null ;
        }
    }

    private static final ObjectMapper objectMapper;
    @SuppressLint("SimpleDateFormat")
    public static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS") ;
    static {
        JsonFactory factory = new JsonFactory();
        factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
        objectMapper = new ObjectMapper();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("UTC"));
        objectMapper.setDateFormat(format);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
        objectMapper.registerModule(new JtsGeometryModule(GeometryUtils.factory()));
        SimpleModule timeModule = new SimpleModule();
//       timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeToLongSerializer());
//        timeModule.addDeserializer(LocalDateTime.class, new LongToLocalDateTimeDeserializer());
        timeModule.addSerializer(Date.class, new LocalDateTimeToStringSerializer());
        timeModule.addDeserializer(Date.class, new StringToLocalDateTimeDeserializer());
        objectMapper.registerModule(timeModule);
    }
    public static ObjectMapper objectMapper() {
        return objectMapper;
    }
}
